package com.cloud.apis.attendance.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateRange;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baidu.aip.face.AipFace;
import com.cloud.apis.attendance.db.dao.AttendanceMapper;
import com.cloud.apis.attendance.pojo.form.*;
import com.cloud.apis.attendance.pojo.vo.*;
import com.cloud.apis.attendance.service.IAttendanceService;
import com.cloud.apis.core.config.BaiduConfig;
import com.cloud.apis.core.exception.CustomException;
import com.cloud.apis.core.model.PageData;
import com.cloud.apis.core.model.Special;
import com.cloud.apis.core.utils.PageInfoToPageDataConverterUtil;
import com.cloud.apis.core.web.ServiceCode;
import com.cloud.apis.document.db.dao.DocumentMapper;
import com.cloud.apis.document.pojo.vo.LeaveVo;
import com.cloud.apis.document.pojo.vo.TravleVo;
import com.cloud.apis.mail.service.MailService;
import com.cloud.apis.message.task.MessageTask;
import com.cloud.apis.message.utils.MessageSendUtil;
import com.cloud.apis.organization.db.dao.AdminMapper;
import com.cloud.apis.user.db.dao.UserMapper;
import com.cloud.apis.user.pojo.vo.UserInfoVo;
import com.cloud.apis.websocket.WebSocketServe;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.codec.binary.Base64;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @Author YinXi
 * @Versin 1.0.0
 * @Date 2024/5/7
 */
@Service
@Slf4j
public class AttendanceService implements IAttendanceService {
    @Autowired
    private AttendanceMapper attendanceMapper;
    @Autowired
    private DocumentMapper documentMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private AdminMapper adminMapper;
    @Autowired
    private BaiduConfig baiduConfig;
    @Autowired
    private MailService mailService;
    @Autowired
    private MessageTask messageTask;
    @Autowired
    private WebSocketServe webSocketServe;
    @Value("${custom-config.default-query-page-size}")
    private Integer defaultQueryPageSize;
    public AttendanceService(){
        log.info("【AttendanceService】");
    }

    @Override
    public Boolean isCheckin(String curDate, Long userId) {
        //当前年-月-日
        String cur = DateUtil.format(new Date(), "yyyy-MM-dd");
        //上班开始打卡时间点
        String attendanceStartTime = cur + " " + attendanceMapper.selectByParamKey("attendance_start_time");
        //上班结束打卡时间点
        String attendanceEndTime = cur + " " + attendanceMapper.selectByParamKey("attendance_end_time");
        //下班开始打卡时间点
        String closingStartTime = cur + " " + attendanceMapper.selectByParamKey("closing_start_time");
        //下班结束打卡时间点
        String closingEndTime = cur + " " + attendanceMapper.selectByParamKey("closing_end_time");
        //判断当前用户是否已经签到
        ArrayList<CheckinVo> checkinVo = attendanceMapper.selectCheckinByData(cur,userId);
       //如果根据当前日期和用户id查询出签到记录
        if (checkinVo.size() > 0) {
            //遍历签到记录
            for (CheckinVo vo : checkinVo) {
                //获取签到创建时间
                String createTime = vo.getCreateTime();
                //将签到创建时间转换为日期时间类型
                DateTime dateTime = DateUtil.parse(createTime);
                //判断当前日期是否是上午
                //如果是
                if(DateUtil.date().isAM()){
                    //判断当前签到记录的创建时间是否是上午
                    if(dateTime.isAM()){
                        // 判断当前签到记录的创建时间是否在上班开始时间点到上班结束时间点之间
                        if (createTime.compareTo(attendanceStartTime) >= 0 && createTime.compareTo(attendanceEndTime) <= 0) {
                            // 已经签到无法再次签到返回false
                            return false;
                        }
                    }
                }
                //否则为下午
                else {
                    //判断当前签到记录的创建时间是否是下午
                    if(dateTime.isPM()){
                        // 判断当前签到记录的创建时间是否在下班开始时间点到下班结束时间点之间
                        if (createTime.compareTo(closingStartTime) >= 0 && createTime.compareTo(closingEndTime) <= 0) {
                            // 已经签到无法再次签到返回false
                            return false;
                        }
                    }
                }
            }
        }
        // 查询当天是否存在特殊考勤记录表中
        Special special = attendanceMapper.selectSpecialByDate(cur);
        // 如果存在
        if (special != null) {
            if (special.getIsWork()) {
                //特殊工作日
                return true;
            } else {
                //特殊休息日
                return false;
            }
        } else {
            //判断是否为周末默认周一到周五为工作日，周六和周日为休息日
            if (DateUtil.date().isWeekend()) {
                //当前是休息日
                return false;
            } else {
                //当前是工作日
                //判断当前是否在可打卡时间段内
                //当前时间点
                String curTime = DateUtil.now();
                //判断当前用户是否请假
                LeaveVo leaveVo = documentMapper.selectLeaveByUserId(userId);
                // 判断用户是否出差
                TravleVo travleVo = documentMapper.selectTravleByUserId(userId);
                // 既不是出差状态也不是请假状态
                if (leaveVo == null && travleVo == null) {
                   //当前时间是上午
                    if(DateUtil.date().isAM()){
                        //当前时间点在上午可打卡时间段内
                        if (curTime.compareTo(attendanceStartTime) >= 0 && curTime.compareTo(attendanceEndTime) <= 0) {
                            //在可打卡时间段内
                            return true;
                        } else {
                            //不在可打卡时间段内
                            return false;
                        }
                    }
                    //当前时间是下午
                    else {
                        // 当前时间点在下午可打卡时间段内
                        if(curTime.compareTo(closingStartTime) >= 0 && curTime.compareTo(closingEndTime) <= 0){
                            //可打卡
                            return true;
                        }else {
                            //不可打卡
                            return false;
                        }
                    }
                }
                //否则
                else {
                    //如果是请假状态
                    if (leaveVo != null) {
                        //获取开始请假时间点
                        String startTime = DateUtil.format(leaveVo.getStartTime(), "yyyy-MM-dd HH:mm:ss");
                        //获取结束请假时间点
                        String endTime = DateUtil.format(leaveVo.getEndTime(), "yyyy-MM-dd HH:mm:ss");
                        //判断请假的时间段是否处于上午
                        if (DateUtil.date().isAM()) {
                            //请假开始时间点处于上班打卡时间段之间的或者是请假结束时间点处于上班打卡时间段之间或之后的
                            if (
                                    //请假开始的时间点处于上班开始打卡的时间点和上班结束打卡的时间点之间
                                    startTime.compareTo(attendanceStartTime) >= 0 && startTime.compareTo(attendanceEndTime) <= 0
                                    ||
                                    //请假结束时间点处于上班开始打卡的时间点和上班结束打卡的时间点之间
                                    endTime.compareTo(attendanceStartTime) >= 0 && endTime.compareTo(attendanceEndTime) <= 0
                                    ||
                                    //请假结束时间点大于上班结束打卡时间点
                                    endTime.compareTo(attendanceEndTime) >= 0
                            ) {
                                //不能打卡
                                return false;
                            }
                            //否则
                            else {
                                //是否在上班打卡时间段中
                                if (
                                        //当前时间点处于上班打卡时间段区间
                                        curTime.compareTo(attendanceStartTime) >= 0 && curTime.compareTo(attendanceEndTime) <= 0
                                ) {
                                    //在可打卡时间段内
                                    return true;
                                } else {
                                    //不在可打卡时间段内
                                    return false;
                                }
                            }
                        }
                        //判断请假的时间段是否处于下午下班的时间段内
                        else {
                            //请假开始时间点处于下班打卡时间段之间的或者是请假结束时间点处于下班打卡时间段之间或之后的
                            if (
                                    //请假开始的时间点处于下班开始打卡的时间点和下班结束打卡的时间点之间
                                    startTime.compareTo(closingStartTime) >= 0 && startTime.compareTo(closingEndTime) <= 0
                                    ||
                                    //请假结束时间点处于下班开始打卡的时间点和下班结束打卡的时间点之间
                                    endTime.compareTo(closingStartTime) >= 0 && endTime.compareTo(closingEndTime) <= 0
                                    ||
                                    //请假结束时间点大于下班结束打卡时间点
                                    endTime.compareTo(closingEndTime) >= 0
                            ) {
                                //不能打卡
                                return false;
                            }
                            //否则
                            else {
                                //是否在下午下班打卡时间段内
                                if (
                                        //当前时间点处于下班打卡时间段区间
                                        curTime.compareTo(closingStartTime) >= 0 && curTime.compareTo(closingEndTime) <= 0
                                ) {
                                    //在可打卡时间段内
                                    return true;
                                }
                                //否则
                                else {
                                    // 不在可打卡时间段内
                                    return false;
                                }
                            }
                        }
                    }
                    //如果是出差状态
                    else {
                        //获取开始出差时间点
                        String startTime = DateUtil.format(travleVo.getStartTime(), "yyyy-MM-dd HH:mm:ss");
                        //获取结束出差时间点
                        String endTime = DateUtil.format(travleVo.getEndTime(), "yyyy-MM-dd HH:mm:ss");
                        //判断出差的时间段是否处于上午
                        if (DateUtil.date().isAM()) {
                            //出差开始时间点处于上班打卡时间段之间的或者是出差结束时间点处于上班打卡时间段之间或之后
                            if (
                                    //出差开始的时间点处于下班开始打卡的时间点和下班结束打卡的时间点之间
                                    startTime.compareTo(attendanceStartTime) >= 0 && startTime.compareTo(attendanceEndTime) <= 0
                                    ||
                                    //出差结束时间点处于下班开始打卡的时间点和下班结束打卡的时间点之间
                                    endTime.compareTo(attendanceStartTime) >= 0 && endTime.compareTo(attendanceEndTime) <= 0
                                    ||
                                    // 出差结束时间点大于下班结束打卡时间点
                                    endTime.compareTo(attendanceEndTime) >= 0
                            ) {
                                //不能打卡
                                return false;
                            }
                            //否则
                            else {
                                //在上午上班打卡时间段内
                                if (
                                        //当前时间点处于上班打卡时间段区间
                                        curTime.compareTo(attendanceStartTime) >= 0 && curTime.compareTo(attendanceEndTime) <= 0
                                ) {
                                    //在可打卡时间段内
                                    return true;
                                } else {
                                    //不在可打卡时间段内
                                    return false;
                                }
                            }
                        }
                        //如果是下午
                        else {
                            //出差开始时间点处于下班打卡时间段之间的或者是出差结束时间点处于下班打卡时间段之间或之后
                            if (
                                    //出差开始的时间点处于下班开始打卡的时间点和下班结束打卡的时间点之间
                                    startTime.compareTo(closingStartTime) >= 0 && startTime.compareTo(closingEndTime) <= 0
                                    ||
                                    //出差结束时间点处于下班开始打卡的时间点和下班结束打卡的时间点之间
                                    endTime.compareTo(closingStartTime) >= 0 && endTime.compareTo(closingEndTime) <= 0
                                    ||
                                    //出差结束时间点大于下班结束打卡时间点
                                    endTime.compareTo(closingEndTime) >= 0)
                            {
                                //不能打卡
                                return false;
                            }
                            //否则
                            else {
                                //在下午下班时间段内
                                if (
                                        //当前时间点处于下班打卡时间段区间
                                        curTime.compareTo(closingStartTime) >= 0 && curTime.compareTo(closingEndTime) <= 0
                                ) {
                                    //在可打卡时间段内
                                    return true;
                                } else {
                                    //不在可打卡时间段内
                                    return false;
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    @Override
    public void checkin(HashMap map) {
        //当前考勤状态为缺勤
        int status = 0;
        //获取当前时间作为打卡时间
        String curTime = DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss");
        //获取当前用户id
        Long userId = (Long) map.get("userId");
        //如果当前用户id存在
        if (userId != null) {
            //判断当前用户是否存在
            if (userMapper.selectUserById(userId) == null) {
                throw new CustomException(ServiceCode.ERROR_BAD_REQUEST.getValue(), "用户不存在");
            }
        }
        //如果当前用户id不存在
        else {
            // 抛出异常
            throw new CustomException(ServiceCode.ERROR_BAD_REQUEST.getValue(), "用户不存在");
        }
        //当前年-月-日
        String cur = DateUtil.format(new Date(), "yyyy-MM-dd");
        //判断当前是早上还是下午
        //如果是上午
        if (DateUtil.date().isAM()) {
            //获取上班打卡开始时间
            String attendanceStartTime = cur + " " + attendanceMapper.selectByParamKey("attendance_start_time");
            //获取上班时间点
            String attendanceTime = cur + " " + attendanceMapper.selectByParamKey("attendance_time");
            //获取上班打卡结束时间点
            String attendanceEndTime = cur + " " + attendanceMapper.selectByParamKey("attendance_end_time");
            //判断当前打卡时间是否再上班开始打卡时间点到上班时间点之间
            if (curTime.compareTo(attendanceStartTime) >= 0 && curTime.compareTo(attendanceTime) <= 0) {
                //当前考勤状态为正常
                status = 1;
            }
            //判断当前打卡时间是否再上班时间点到上班打卡结束时间之间
            else if (curTime.compareTo(attendanceTime) >= 0 && curTime.compareTo(attendanceEndTime) <= 0) {
                //当前考勤状态为迟到
                status = 2;
            }
        }
        // 如果是下午
        else {
            //获取下班打卡开始时间
            String closingStartTime = cur + " " + attendanceMapper.selectByParamKey("closing_start_time");
            //获取下班时间点
            String closingTime = cur + " " + attendanceMapper.selectByParamKey("closing_time");
            //获取下班打卡结束时间点
            String closingEndTime = cur + " " + attendanceMapper.selectByParamKey("closing_end_time");
            //判断当前打卡时间是否再下班开始打卡时间点到下班时间点之间
            if (curTime.compareTo(closingStartTime) >= 0 && curTime.compareTo(closingTime) <= 0) {
                //当前考勤状态为早退
                status = 3;
            }
            //判断当前打卡时间是否再下班时间点到下班打卡结束时间之间
            else if (curTime.compareTo(closingTime) >= 0 && curTime.compareTo(closingEndTime) <= 0) {
                //当前考勤状态为正常
                status = 1;
            }
        }
        //根据当前用户id查询对应的人脸模型
        FaceVo faceVo = attendanceMapper.selectFaceByUserId(userId);
        //判断人脸模型是否为空
        if (faceVo == null) {
            throw new CustomException(ServiceCode.ERROR_NO_PEOPLE.getValue(), "人脸模型不存在");
        } else {
            byte[] fileByte = null;
            //获取图片的Url路径
            String path = (String) map.get("path");
            if (!detect(path)) {
                throw new CustomException(ServiceCode.ERROR_BAD_REQUEST.getValue(), "图片中不存在人脸");
            }
            try {
                File file = new File(path);
                fileByte = Files.readAllBytes(file.toPath());
                String faceBase = Base64.encodeBase64String(fileByte);
                Double num = checkUser(faceBase, baiduConfig.aipFace());
                //非该用户
                if (num < 95) {
                    throw new CustomException(ServiceCode.ERROR_NOT_IMAGE.getValue(), "非本人签到请联系工作人员");
                } else {
                    //获取map信息
                    String nation = (String) map.get("nation");
                    String province = (String) map.get("province");
                    String city = (String) map.get("city");
                    String district = (String) map.get("district");
                    String street = (String) map.get("street");
                    String streetNumber = (String) map.get("streetNumber");
                    //获取管理员设置的考勤地点
                    AddressVo addressVo = attendanceMapper.selectAddress();
                    System.out.println(addressVo);
                    if (addressVo != null) {
                        if(!addressVo.getNation().equals(nation)){
                            throw new CustomException(ServiceCode.ERROR_BAD_ADDRESS.getValue(), "当前位置无法签到,不在签到的国家");
                        }else if(!addressVo.getProvince().equals(province)){
                            throw new CustomException(ServiceCode.ERROR_BAD_ADDRESS.getValue(), "当前位置无法签到,不在签到的省份");
                        }else if(!addressVo.getCity().equals(city)){
                            throw new CustomException(ServiceCode.ERROR_BAD_ADDRESS.getValue(), "当前位置无法签到,不在签到的城市");
                        }else if(!addressVo.getDistrict().equals(district)){
                            throw new CustomException(ServiceCode.ERROR_BAD_ADDRESS.getValue(), "当前位置无法签到,不在签到的区域");
                        }else if(!addressVo.getStreet().equals(street)){
                            throw new CustomException(ServiceCode.ERROR_BAD_ADDRESS.getValue(), "当前位置无法签到,不在签到的街道");
                        }
                    }
                    //封装checkinForm
                    CheckinForm checkinForm = new CheckinForm();
                    checkinForm.setNation(nation);
                    checkinForm.setProvince(province);
                    checkinForm.setCity(city);
                    checkinForm.setDistrict(district);
                    checkinForm.setStreet(street);
                    checkinForm.setStreetNumber(streetNumber);
                    checkinForm.setStatus(status);
                    checkinForm.setUserId(userId);
                    checkinForm.setData(cur);
                    //插入签到信息
                    int number = attendanceMapper.insertCheckin(checkinForm);
                    if (number <= 0) {
                        throw new CustomException(ServiceCode.ERROR_BAD_REQUEST.getValue(), "签到失败");
                    }
                    //获取当前签到记录
                    CheckinVo checkinVo = attendanceMapper.selectCheckinById(checkinForm.getId());
                    //获取管理当前用户的管理者
                    ArrayList<UserInfoVo> adminUsers = adminMapper.selectadminByOrganizationId(checkinVo.getUser().getOrganizationId());
                    //获取管理者的邮箱
                    ArrayList<String> emails = new ArrayList<>();
                    for (UserInfoVo user : adminUsers) {
                        emails.add(user.getEMail());
                    }
                    //将ArrayList<String> emails转换为数组
                    String[] receivers = new String[emails.size()];
                    for (int i = 0; i < receivers.length; i++) {
                        receivers[i] = emails.get(i);
                    }
                    //如果是迟到
                    if (status == 2) {
                        //将该异常邮件发送给相关的管理者
                        mailService.sendException(checkinVo.getId(), receivers);
                        //将该异常发送到打卡异常员工的消息模块
                        String content = "您当前打卡时间" + cur + "打卡迟到，请联系相关管理者进行处理";
                        MessageSendUtil.sendSimpleMessage(messageTask, userId, "打卡异常提醒", content);
                    }
                    //如果是早退
                    if (status == 3) {
                        //将该异常邮件发送给相关的管理者
                        mailService.sendException(checkinVo.getId(), receivers);
                        //将该异常发送到打卡异常员工的消息模块
                        String content = "您当前打卡时间" + cur + "打卡早退，请联系相关管理者进行处理";
                        MessageSendUtil.sendSimpleMessage(messageTask, userId, "打卡异常提醒", content);
                    }
                    webSocketServe.sendMessage(userId);
                }
            } catch (IOException e) {
                throw new CustomException(ServiceCode.ERROR_BAD_REQUEST.getValue(), "图片中不存在人脸");
            }
        }
    }

    @Override
    public void createFaceModel(Long userId, String path) {
        byte[] fileByte = null;
        try {
            File file = new File(path);
            if (!detect(path)) {
                throw new CustomException(ServiceCode.ERROR_BAD_REQUEST.getValue(), "未识别到人脸");
            }
            fileByte = Files.readAllBytes(file.toPath());
            String faceBase = Base64.encodeBase64String(fileByte);
            if (faceSetAddUser(baiduConfig.aipFace(), faceBase, userId + "")) {
                FaceForm form = new FaceForm();
                form.setUserId(userId);
                form.setModel(path);
                //将返回的人脸数据模型存储到数据库中
                int num = attendanceMapper.insertFace(form);
                if (num <= 0) {
                    throw new CustomException(ServiceCode.ERROR_BAD_REQUEST.getValue(), "人脸模型创建失败");
                }
            } else {
                throw new CustomException(ServiceCode.ERROR_BAD_REQUEST.getValue(), "无法识别到人脸,请重试");
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw new CustomException(ServiceCode.ERROR_BAD_REQUEST.getValue(), "服务器异常请稍后重试");
        }
    }

    @Override
    public PageData<SpecialVo> specialList(SpecialListForm form) {
        return specialListPage(form.getPageNum(), defaultQueryPageSize, form);
    }

    @Override
    public PageData<SpecialVo> specialListPage(Integer pageNum, Integer pageSize, SpecialListForm form) {
        PageHelper.startPage(pageNum, pageSize);
        List<SpecialVo> list = attendanceMapper.specialListPage();
        PageInfo<SpecialVo> pageInfo = new PageInfo<>(list);
        return PageInfoToPageDataConverterUtil.convert(pageInfo);
    }

    @Override
    public SpecialVo specialAdd(SpecialAddForm form) {
        int num = attendanceMapper.insertSpecial(form);
        if (num <= 0) {
            throw new CustomException(ServiceCode.ERROR_BAD_REQUEST.getValue(), "添加特殊考勤失败");
        }
        return attendanceMapper.selectSpecialById(form.getId());
    }

    @Override
    public void deleteSpecialAttendance(Long id) {
        int num = attendanceMapper.deleteSpecialAttendance(id);
        if (num <= 0) {
            throw new CustomException(ServiceCode.ERROR_BAD_REQUEST.getValue(), "删除特殊考勤失败");
        }
    }

    @Override
    public ArrayList<SysVo> sys(Long[] ids) {
        return attendanceMapper.sys(ids);
    }

    @Override
    public void reset(Long[] ids) {
        int num = attendanceMapper.reset(ids);
        if (num <= 0) {
            throw new CustomException(ServiceCode.ERROR_BAD_REQUEST.getValue(), "重置系统参数失败");
        }
    }

    @Override
    public void setSys(SysForm form) {
        ArrayList<String> values = new ArrayList<>();
        values.add(form.getAttendanceStartTime());
        values.add(form.getAttendanceTime());
        values.add(form.getAttendanceEndTime());
        values.add(form.getClosingStartTime());
        values.add(form.getClosingTime());
        values.add(form.getClosingEndTime());
        String[] v = new String[values.size()];
        for (int i = 0; i < values.size(); i++) {
            v[i] = values.get(i);
        }
        for (int i = 0; i < form.getIds().length; i++) {
            int num = attendanceMapper.setSys(form.getIds()[i],v[i]);
            if (num <= 0) {
                throw new CustomException(ServiceCode.ERROR_BAD_REQUEST.getValue(), "设置系统参数失败");
            }
        }
    }

    @Override
    public AddressVo getPosition() {
        return attendanceMapper.getPosition();
    }

    @Override
    public void resetPosition(ResetPositionForm form) {
        int num = attendanceMapper.resetPosition(form);
        if (num <= 0) {
            throw new CustomException(ServiceCode.ERROR_BAD_REQUEST.getValue(), "重置考勤位置失败");
        }
    }

    @Override
    public ArrayList<HashMap> searchMonthCheckin(Long userId, Integer year, Integer month) {
        UserInfoVo user = userMapper.selectUserById(userId);
        //获取当前用户的入职日期
        String hireDateStr=null;
        //入职时的年份
        int hireYear = 0;
        //入职时的月份
        int hireMonth = 0;
        //入职时的具体日期
        int hireDay = 0;
        if(user != null){
            LocalDateTime hireDate = user.getCreateTime();
            if(hireDate != null){
                //获取当前用户的入职年份
                hireYear = hireDate.getYear();
                //获取当前用户的入职月份
                hireMonth = hireDate.getMonthValue();
                //获取当前用户的入职日期
                hireDay = hireDate.getDayOfMonth();
                //组合成该用户的入职日期
                hireDateStr = hireYear + "-" + (hireMonth<10?"0"+hireMonth:hireMonth) + "-" + (hireDay<10?"0"+hireDay:hireDay);
            }else{
                throw new CustomException(ServiceCode.ERROR_BAD_REQUEST.getValue(), "用户不存在");
            }
        }else{
            throw new CustomException(ServiceCode.ERROR_BAD_REQUEST.getValue(), "用户不存在");
        }
        //将用户的入职日期转换未DateTime对象
        DateTime hireDate = DateUtil.parse(hireDateStr);
        //获取用户入职时的开始月份
        DateTime startDate = DateUtil.parse(year+"-"+(month>10?"0"+month:month)+"-01");
        if(startDate.isBefore(DateUtil.beginOfMonth(hireDate))){
            throw new CustomException(ServiceCode.ERROR_BAD_REQUEST.getValue(), "当前月您未入职");
        }
        if(startDate.isBefore(hireDate)){
            startDate = hireDate;
        }
        DateTime endDate = DateUtil.endOfMonth(startDate);
        HashMap map = new HashMap();
        map.put("userId", userId);
        map.put("startDate", startDate.toString());
        map.put("endDate", endDate.toString());
        //获取当月的信息
        ArrayList<HashMap> list = searchWeekCheckin(map);
        return list;
    }

    @Override
    public ArrayList<HashMap> searchWeekCheckin(HashMap param) {
        //        查询用户在本周的考勤情况，包括特殊节假日和工作日
        ArrayList<HashMap> checkinList = attendanceMapper.searchWeekCheckin(param);
//        查询本周特殊的节假日
        ArrayList<String> holidaysList = attendanceMapper.searchHolidaysInRange(param);
//        查询本周特殊的工作日
        ArrayList<String> workdayList = attendanceMapper.searchWorkdayInRange(param);
//        获取本周的开始日期
        DateTime startDay = DateUtil.parseDate(param.get("startDate").toString());
//        获取本周的结束日期
        DateTime endDay = DateUtil.parseDate(param.get("endDate").toString());
//        生成本周七天的日期对象,第三个参数是单位也就是每隔一天生成一个日期对象
        DateRange range = DateUtil.range(startDay,endDay, DateField.DAY_OF_MONTH);
        ArrayList<HashMap> list = new ArrayList<>();
//        有了日期对象可以拿出每一个日期去看今天是工作日还是节假日
        range.forEach(one->{
//            转换为正确的日期格式
            String date = one.toString("yyyy-MM-dd");
//            正常判断是不是工作日还是休息日，也就是周一到周五是工作日，周六周日是休息日
            String type = "工作日";
            if(one.isWeekend()){
                type = "节假日";
            }
//            修正，判断这天是不是特殊工作日或者节假日
            if (holidaysList!=null&&holidaysList.contains(date)){
                type = "节假日";
            } else if (workdayList!=null&&workdayList.contains(date)) {
                type = "工作日";
            }
//            如果是工作日，判断当前签到状态
            String status = "";
            if(type.equals("工作日")&&DateUtil.compare(one,DateUtil.date())<=0){
                status = "缺勤";
                boolean flage = false;
//                如果考勤了但是考勤没有结束的话
                for(HashMap<String,String> map:checkinList){
                    if(map.containsValue(date)){
                        status = map.get("status");
                        flage = true;
                        break;
                    }
                }
                DateTime endTime = DateUtil.parse(DateUtil.today()+" "+attendanceMapper.selectByParamKey("attendance_end_time"));
                String today = DateUtil.today();
//                如果没有考勤并且考勤没有结束的话
                if(date.equals(today)&&DateUtil.date().isBefore(endTime)&&flage==false){
                    status="";
                }
            }
            HashMap map = new HashMap();
            map.put("date",date);
            map.put("status",status);
            map.put("type",type);
            map.put("day",one.dayOfWeekEnum().toChinese("周"));
            list.add(map);
        });
        return list;
    }

    @Override
    public HashMap searchTodayCheckin(Long userId) {
        return attendanceMapper.searchTodayCheckin(userId);
    }

    @Override
    public long searchCheckinDays(Long userId) {
        return attendanceMapper.searchCheckinDays(userId);
    }

    @Override
    public ArrayList<HashMap> weekCheckin(Long userId) {
        UserInfoVo user = userMapper.selectUserById(userId);
        //获取当前用户的入职日期
        String hireDateStr=null;
        //入职时的年份
        int hireYear = 0;
        //入职时的月份
        int hireMonth = 0;
        //入职时的具体日期
        int hireDay = 0;
        if(user != null){
            LocalDateTime hireDate = user.getCreateTime();
            if(hireDate != null){
                //获取当前用户的入职年份
                hireYear = hireDate.getYear();
                //获取当前用户的入职月份
                hireMonth = hireDate.getMonthValue();
                //获取当前用户的入职日期
                hireDay = hireDate.getDayOfMonth();
                //组合成该用户的入职日期
                hireDateStr = hireYear + "-" + (hireMonth<10?"0"+hireMonth:hireMonth) + "-" + (hireDay<10?"0"+hireDay:hireDay);
            }else{
                throw new CustomException(ServiceCode.ERROR_BAD_REQUEST.getValue(), "用户不存在");
            }
        }else{
            throw new CustomException(ServiceCode.ERROR_BAD_REQUEST.getValue(), "用户不存在");
        }
        //将用户的入职日期转换未DateTime对象
        DateTime hiredDate = DateUtil.parse(hireDateStr);
        DateTime startDate = DateUtil.beginOfWeek(DateUtil.date());
        if(startDate.isBefore(hiredDate)){
            startDate=hiredDate;
        }
        DateTime endDate = DateUtil.endOfWeek(DateUtil.date());
        HashMap param = new HashMap();
        param.put("startDate",startDate.toString());
        param.put("endDate",endDate.toString());
        param.put("userId",userId);
        return attendanceMapper.searchWeekCheckin(param);
    }

    /**
     * 注册人脸模型
     */
    public boolean faceSetAddUser(AipFace client, String faceBase, String username) {
        // 参数为数据库中注册的人脸
        HashMap<String, String> options = new HashMap<String, String>();
        options.put("user_info", "user's info");
        JSONObject res = client.addUser(faceBase, "BASE64", "user_01", username, options);
        try {
            System.out.println("注册的人脸识别的数据：" + res.toString(2));
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
        return true;
    }

    /**
     * 检测图片中是否包含人脸
     */
    public boolean detect(String imageUrl) {
        String imageType = "BASE64";
        HashMap<String, Object> options = new HashMap<String, Object>();
        options.put("face_field", "age");
        options.put("max_face_num", "2");
        options.put("face_type", "LIVE");
        options.put("liveness_control", "LOW");
        byte[] fileByte = null;
        File file = new File(imageUrl);
        try {
            fileByte = Files.readAllBytes(file.toPath());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        String faceBase = Base64.encodeBase64String(fileByte);
        // 人脸检测
        JSONObject res = baiduConfig.aipFace().detect(faceBase, imageType, options);
        Integer error_code = null;
        try {
            error_code = (Integer) res.get("error_code");
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
        return error_code == 0;
    }

    /**
     * 人脸对比
     */
    public Double checkUser(String imgBash64, AipFace client) {
        // 传入可选参数调用接口
        HashMap<String, Object> options = new HashMap<>();
        JSONObject res = client.search(imgBash64, "BASE64", "user_01", options);
        System.out.println();
        JSONObject user = null;
        try {
            user = (JSONObject) res.getJSONObject("result").getJSONArray("user_list").get(0);
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
        Double score = null;
        try {
            score = (Double) user.get("score");
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
        System.out.println("人脸比对结果：" + user);
        return score;
    }
}
